package io.sunny.platform.backend.starter.compression;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.WriteListener;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletResponseWrapper;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;

/**
 * @Author SUNNY
 * @Date 2025/7/19 14:56
 * @PackageName: io.sunny.platform.starter.compression
 * @Description: Filter 级（Deflate 实现方式）
 * @Version 1.0
 */
public class DeflateCompressionFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        String ae = request.getHeader("Accept-Encoding");
        if (ae != null && ae.contains("deflate")) {
            DeflateServletResponseWrapper wrapper = new DeflateServletResponseWrapper(response);
            try {
                chain.doFilter(request, wrapper);
            } finally {
                wrapper.finish();
            }
        } else {
            chain.doFilter(request, response);
        }
    }

    /**
     * 自定义响应包装器
     */
    static class DeflateServletResponseWrapper extends HttpServletResponseWrapper {

        private DeflaterOutputStream deflaterOutputStream;
        private ServletOutputStream out;

        public DeflateServletResponseWrapper(HttpServletResponse response) {
            super(response);
        }

        @Override
        public ServletOutputStream getOutputStream() throws IOException {
            if (out == null) {
                super.setHeader("Content-Encoding", "deflate");
                deflaterOutputStream = new DeflaterOutputStream(super.getOutputStream(),
                        new Deflater(Deflater.BEST_SPEED));
                out = new ServletOutputStream() {
                    @Override
                    public boolean isReady() {
                        return true;
                    }

                    @Override
                    public void setWriteListener(WriteListener writeListener) {
                    }

                    @Override
                    public void write(int b) throws IOException {
                        deflaterOutputStream.write(b);
                    }
                };
            }
            return out;
        }

        public void finish() throws IOException {
            if (deflaterOutputStream != null) {
                deflaterOutputStream.finish();
                deflaterOutputStream.close();
            }
        }
    }
}
